/*
 *  ckr_spec_container_specs.cpp
 *  ckrSpec
 *
 *  Created by C. Keith Ray on 2006.11.05.
 *  Copyright 2006 __MyCompanyName__. All rights reserved.
 *
 */

#import "ckr_spec_cpp_specs.h"
#import "ckr_spec_cpp.h"

#include <iostream>
#include <sstream>
#include <vector>
#include <deque>
#include <ostream>

#include <assert.h>

using namespace std;
using namespace ckr;

//  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

static void	vector_does_not_contain_in_should_contain_reports_failure();
static void	vector_does_contain_in_should_contain_reports_nothing();

static void	deque_does_not_contain_in_should_contain_reports_failure();
static void	deque_does_contain_in_should_contain_reports_nothing();

static void	deque_does_contain_in_should_not_contain_reports_failure();
static void	deque_does_not_contain_in_should_not_contain_reports_nothing();

static void vectors_equal_in_should_equal_reports_nothing();
static void vectors_not_equal_in_should_equal_reports_failure();

//  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

void run_container_specs()
{
	vector_does_not_contain_in_should_contain_reports_failure();
	vector_does_contain_in_should_contain_reports_nothing();

	deque_does_not_contain_in_should_contain_reports_failure();
	deque_does_contain_in_should_contain_reports_nothing();

	deque_does_contain_in_should_not_contain_reports_failure();
	deque_does_not_contain_in_should_not_contain_reports_nothing();

	vectors_equal_in_should_equal_reports_nothing();
	vectors_not_equal_in_should_equal_reports_failure();
}

//  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

DECLARE_SPEC(Vector_does_not_contain_in_should_contain);

void Vector_does_not_contain_in_should_contain::spec()
{
	std::vector<int> aVector;
	aVector.push_back( 1 );
	aVector.push_back( 3 );	

	CONTAINER(aVector).SHOULD_CONTAIN(2); // fail msg expected
}

static void vector_does_not_contain_in_should_contain_reports_failure()
{
	Vector_does_not_contain_in_should_contain aContext;
	
	RecordingFailuresSpecListener listener;
	aContext.run_spec( & listener );
	std::string actual = listener.logStr();
	
	const std::string expected("aVector should contain 2 (2) FAILED in Vector_does_not_contain_in_should_contain; line");

	std::string::size_type foundPos = actual.find( expected, 0 );
	assert( foundPos != std::string::npos );
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

DECLARE_SPEC(Vector_does_contain_in_should_contain);

void Vector_does_contain_in_should_contain::spec()
{
	std::vector<int> aVector;
	aVector.push_back( 1 );
	aVector.push_back( 2 );	
	aVector.push_back( 3 );	

	CONTAINER(aVector).SHOULD_CONTAIN(2); // no msg expected
}

static void vector_does_contain_in_should_contain_reports_nothing()
{
	Vector_does_contain_in_should_contain aContext;
	
	RecordingFailuresSpecListener listener;
	aContext.run_spec( & listener );
	std::string actual = listener.logStr();

	const std::string expected;

	assert( expected == actual );
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

/* now that this is working for vector, make it work for deque, generalizing
   the AssertableContainer template.
*/

DECLARE_SPEC(Deque_does_not_contain_in_should_contain);

void Deque_does_not_contain_in_should_contain::spec()
{
	std::deque<int> aDeque;
	aDeque.push_back( 1 );
	aDeque.push_back( 3 );	

	CONTAINER(aDeque).SHOULD_CONTAIN(2); // fail msg expected
}

static void deque_does_not_contain_in_should_contain_reports_failure()
{
	Deque_does_not_contain_in_should_contain aContext;
	
	RecordingFailuresSpecListener listener;
	aContext.run_spec( & listener );
	std::string actual = listener.logStr();
	
	const std::string expected("aDeque should contain 2 (2) FAILED in Deque_does_not_contain_in_should_contain; line");

	std::string::size_type foundPos = actual.find( expected, 0 );
	assert( foundPos != std::string::npos );
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

DECLARE_SPEC(Deque_does_contain_in_should_contain);

void Deque_does_contain_in_should_contain::spec()
{
	std::deque<int> aDeque;
	aDeque.push_back( 1 );
	aDeque.push_back( 2 );	
	aDeque.push_back( 3 );	

	CONTAINER(aDeque).SHOULD_CONTAIN(2); // no msg expected
}

static void deque_does_contain_in_should_contain_reports_nothing()
{
	Deque_does_contain_in_should_contain aContext;
	
	RecordingFailuresSpecListener listener;
	aContext.run_spec( & listener );
	std::string actual = listener.logStr();

	const std::string expected;

	assert( expected == actual );
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

DECLARE_SPEC(Deque_does_contain_in_should_not_contain);

void Deque_does_contain_in_should_not_contain::spec()
{
	std::deque<int> aDeque;
	aDeque.push_back( 1 );
	aDeque.push_back( 3 );	

	CONTAINER(aDeque).SHOULD_NOT_CONTAIN(1); // fail msg expected
}

static void deque_does_contain_in_should_not_contain_reports_failure()
{
	Deque_does_contain_in_should_not_contain aContext;
	
	RecordingFailuresSpecListener listener;
	aContext.run_spec( & listener );
	std::string actual = listener.logStr();
	
	const std::string expected("aDeque should not contain 1 (1) FAILED in Deque_does_contain_in_should_not_contain; line");

	std::string::size_type foundPos = actual.find( expected, 0 );
	assert( foundPos != std::string::npos );
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

DECLARE_SPEC(Deque_does_not_contain_in_should_not_contain);

void Deque_does_not_contain_in_should_not_contain::spec()
{
	std::deque<int> aDeque;
	aDeque.push_back( 1 );
	aDeque.push_back( 3 );	

	CONTAINER(aDeque).SHOULD_NOT_CONTAIN(2); // no msg expected
}

static void deque_does_not_contain_in_should_not_contain_reports_nothing()
{
	Deque_does_not_contain_in_should_not_contain aContext;
	
	RecordingFailuresSpecListener listener;
	aContext.run_spec( & listener );
	std::string actual = listener.logStr();

	const std::string expected;

	assert( expected == actual );
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// comparing two vectors equal should work, as long == works on the 
// values in the vector. Also, AssertableValue<> will try instantiate 
// a call to operator<< for IntVector, so we need to define that.

typedef std::vector<int> IntVector;

std::ostream& 
operator<<( std::ostream& ostrm, const IntVector& iv )
{
	ostrm << "IntVector(";
	for ( IntVector::const_iterator i = iv.begin(); i != iv.end(); ++i )
	{
		ostrm << (*i) << ", ";
	}
	ostrm << ")";

	return ostrm;
}

DECLARE_SPEC(Vectors_equal_in_should_equal);

void Vectors_equal_in_should_equal::spec()
{
	IntVector left;
	left.push_back( 1 );
	left.push_back( 3 );	

	IntVector right;
	right.push_back( 1 );
	right.push_back( 3 );	

	VALUE(left).SHOULD_EQUAL(right); // no msg expected
}

static void vectors_equal_in_should_equal_reports_nothing()
{
	Vectors_equal_in_should_equal aContext;
	
	RecordingFailuresSpecListener listener;
	aContext.run_spec( & listener );
	std::string actual = listener.logStr();

	const std::string expected;

	assert( expected == actual );
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

DECLARE_SPEC(Vectors_not_equal_in_should_equal);

void Vectors_not_equal_in_should_equal::spec()
{
	IntVector left;
	left.push_back( 1 );
	left.push_back( 3 );	

	IntVector right;
	right.push_back( 1 );
	right.push_back( 5 );	

	VALUE(left).SHOULD_EQUAL(right); // fail msg expected
}

static void vectors_not_equal_in_should_equal_reports_failure()
{
	Vectors_not_equal_in_should_equal aContext;
	
	RecordingFailuresSpecListener listener;
	aContext.run_spec( & listener );
	std::string actual = listener.logStr();

	const std::string expected("left (IntVector(1, 3, )) should equal right (IntVector(1, 5, )) FAILED in Vectors_not_equal_in_should_equal; line");

	std::string::size_type foundPos = actual.find( expected, 0 );
	assert( foundPos != std::string::npos );
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

